package su.msk.jet.team01.chatik.server.data;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.naming.InvalidNameException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import su.msk.jet.team01.chatik.server.db.DatabaseAdapter;
import su.msk.jet.team01.chatik.server.exception.ClientNotFoundException;
import su.msk.jet.team01.chatik.server.exception.NameInUseException;

public class ClientManager {

	private static final String EXCEPTION_MSG_USER_NOT_FOUND = "User '%s' not found";

	private static final String EXCEPTION_MSG_NAME_IS_IN_USE = "Name '%s' is already in use.";

	private static final String EXCEPTION_MSG_INVALID_NAME = "Invalid name specified";

	private Map<String, Client> clients = new HashMap<String, Client>();

	private static DatabaseAdapter database = DatabaseAdapter.getInstance();

	private static Logger logger = LoggerFactory.getLogger(ClientManager.class);

	private static final String SQL_QUERY_SELECT_USER_ID = "SELECT id FROM users WHERE name=?";

	protected ClientManager() {
		
	}
	
	public void addClient(final Client client) {
		synchronized (clients) {
			clients.put(client.getName(), client);
		}
	}

	public void changeClientName(final Client client, final String newName)
			throws InvalidNameException, NameInUseException {
		Client newClient;

		if (newName.isEmpty()) {
			throw new InvalidNameException(EXCEPTION_MSG_INVALID_NAME);
		}

		synchronized (clients) {

			newClient = clients.get(newName);
			if (newClient != null) {
				throw new NameInUseException(EXCEPTION_MSG_NAME_IS_IN_USE,
						newName);
			}
			
			removeClient(client);
			client.setName(newName);
			addClient(client);
		}
	}

	public Client getClient(final String name) throws ClientNotFoundException {
		Client client;

		synchronized (clients) {
			client = clients.get(name);
		}

		if (client == null) {
			throw new ClientNotFoundException(EXCEPTION_MSG_USER_NOT_FOUND,
					name);
		}

		return client;
	}

	public int getClientDatabaseID(final String name) {
		List<Map<String, Object>> res;
		int id = -1;

		if (name.isEmpty()) {
			return id;
		}

		try {
			res = database.executeQuery(SQL_QUERY_SELECT_USER_ID, name);
			if (res.size() != 0) {
				id = (Integer) res.get(0).get("ID");
			} else {
				id = database.executeInsert(
						"INSERT INTO users (name) VALUES (?)", name);
			}
		} catch (SQLException ex) {
			logger.error(ex.getMessage(), ex);
		}

		return id;
	}

	public void removeClient(final Client client) {
		synchronized (clients) {
			clients.remove(client.getName());
		}
	}

}
